Imports System
Imports System.Collections.Generic
Imports System.Text



Public Enum ParserFuncDef_ItemType
    Alternative
    Designator
    Separator
    Expression
    OptionalGroup
    Parentesis
End Enum

Public Enum ParserFuncDef_DesignatorType
    Designator
    Seperator
End Enum

Public Enum ParserFuncDef_OptionalRepeatType
    Group
    [Optional]
    RepeatOptional
    Repeat
End Enum

Public Class ParserFuncDef
    Private _Items As New ParserFuncDef_ItemList()
    Private _Name As String
    Private _Group As String
    Private _Description As String
    Private _Return As ParserFuncDef_Expression

    Private Sub TranslateProduction(ByVal SrcNode As System.Xml.XmlNode, ByVal DstList As ParserFuncDef_ItemList, ByVal Parent As ParserFuncDef_Item)
        For Each SubNode As System.Xml.XmlNode In SrcNode.ChildNodes
            Select Case SubNode.Name
                Case "Alternative"
                    Dim Alternative As New ParserFuncDef_Alternative(New ParserFuncDef_ItemList(), Parent)
                    TranslateProduction(SubNode, Alternative.Children, Alternative)
                    DstList.Add(Alternative)
                    Exit Select

                Case "Designator"
                    Dim DesignatorValue As String = SubNode.InnerText.Trim()
                    Dim DesignatorType As ParserFuncDef_DesignatorType = Nothing
                    If SubNode.Attributes("Type").Value.ToUpper() = "SEPARATOR" Then
                        DesignatorType = ParserFuncDef_DesignatorType.Seperator
                    Else
                        DesignatorType = ParserFuncDef_DesignatorType.Designator
                    End If

                    Dim Designator As New ParserFuncDef_Designator(DesignatorValue, DesignatorType, Parent)
                    DstList.Add(Designator)
                    Exit Select

                Case "Expression"
                    Dim ExprName As String = SubNode.Attributes("Name").Value
                    Dim ExprDescr As String = SubNode.Attributes("Description").Value
                    Dim ExprType As ReturnType = Nothing
                    If SubNode.Attributes("Type") Is Nothing Then
                        ExprType = ReturnType.Any
                    Else
                        Select Case SubNode.Attributes("Type").Value.ToUpper()
                            Case "BOOLEAN"
                                ExprType = ReturnType.[Boolean]
                                Exit Select
                            Case "DATE"
                                ExprType = ReturnType.[Date]
                                Exit Select
                            Case "NUMBER"
                                ExprType = ReturnType.Number
                                Exit Select
                            Case "STRING"
                                ExprType = ReturnType.[String]
                                Exit Select
                            Case Else
                                ExprType = ReturnType.Any
                                Exit Select
                        End Select
                    End If


                    Dim Expression As New ParserFuncDef_Expression(ExprName, ExprType, ExprDescr, Parent)
                    DstList.Add(Expression)
                    Exit Select

                Case "OptionalGroup"
                    Dim GroupRepeatType As ParserFuncDef_OptionalRepeatType = Nothing
                    If SubNode.Attributes("RepeatType") Is Nothing Then
                        GroupRepeatType = ParserFuncDef_OptionalRepeatType.[Optional]
                    Else
                        Select Case SubNode.Attributes("RepeatType").Value
                            Case "*"
                                GroupRepeatType = ParserFuncDef_OptionalRepeatType.RepeatOptional
                                Exit Select
                            Case "+"
                                GroupRepeatType = ParserFuncDef_OptionalRepeatType.Repeat
                                Exit Select
                            Case "?"
                                GroupRepeatType = ParserFuncDef_OptionalRepeatType.[Optional]
                                Exit Select
                            Case Else
                                GroupRepeatType = ParserFuncDef_OptionalRepeatType.Group
                                Exit Select
                        End Select
                    End If


                    Dim OptionalGroup As New ParserFuncDef_OptionalGroup(New ParserFuncDef_ItemList(), GroupRepeatType, Parent)
                    TranslateProduction(SubNode, OptionalGroup.Children, OptionalGroup)
                    DstList.Add(OptionalGroup)
                    Exit Select

                Case "Parentesis"
                    Dim Parentesis As New ParserFuncDef_Parentesis(New ParserFuncDef_ItemList(), Parent)
                    TranslateProduction(SubNode, Parentesis.Children, Parentesis)
                    DstList.Add(Parentesis)
                    Exit Select

            End Select
        Next
    End Sub

    Public Sub New(ByVal XMLdef As System.Xml.XmlNode)
        If XMLdef.Name = "Function" Then
            _Group = XMLdef.Attributes("Group").Value

            For Each SubNode As System.Xml.XmlNode In XMLdef.ChildNodes
                If SubNode.Name = "FunctionName" Then
                    _Name = SubNode.InnerText.Trim()
                    Continue For
                End If


                If SubNode.Name = "Description" Then
                    _Description = SubNode.InnerText.Trim()
                    Continue For
                End If


                If SubNode.Name = "ReturnValue" Then
                    Dim tmpRetValName As String = SubNode.Attributes("Name").Value
                    Dim tmpRetValDescr As String = Nothing
                    If (SubNode.Attributes("Description") IsNot Nothing) Then
                        tmpRetValDescr = SubNode.Attributes("Description").Value
                    Else
                        tmpRetValDescr = ""
                    End If

                    Dim tmpRetValType As ReturnType = Nothing
                    Select Case SubNode.Attributes("Type").Value.ToUpper()
                        Case "BOOLEAN"
                            tmpRetValType = ReturnType.[Boolean]
                            Exit Select
                        Case "DATE"
                            tmpRetValType = ReturnType.[Date]
                            Exit Select
                        Case "NUMBER"
                            tmpRetValType = ReturnType.Number
                            Exit Select
                        Case "STRING"
                            tmpRetValType = ReturnType.[String]
                            Exit Select
                        Case Else
                            tmpRetValType = ReturnType.Any
                            Exit Select
                    End Select
                    _Return = New ParserFuncDef_Expression(tmpRetValName, tmpRetValType, tmpRetValDescr, Nothing)
                    Continue For
                End If

                If SubNode.Name = "Production" Then
                    TranslateProduction(SubNode, _Items, Nothing)
                End If
            Next
        Else

            Throw New Exception("Invalid XML Function Definition")
        End If

    End Sub

    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property

    Public Property Description() As String
        Get
            Return _Description
        End Get
        Set(ByVal value As String)
            _Description = value
        End Set
    End Property

    Public Property [Return]() As ParserFuncDef_Expression
        Get
            Return _Return
        End Get
        Set(ByVal value As ParserFuncDef_Expression)
            _Return = value
        End Set
    End Property

    Public Property Group() As String
        Get
            Return _Group
        End Get
        Set(ByVal value As String)
            _Group = value
        End Set
    End Property

    Public ReadOnly Property Items() As ParserFuncDef_ItemList
        Get
            Return _Items
        End Get
    End Property


    Public Overloads Overrides Function ToString() As String
        Dim buffer As New System.Text.StringBuilder()
        For i As Integer = 0 To _Items.Count - 1
            buffer.Append(_Items(i).ToString())
            If i > 0 Then
                buffer.Append(" ")
            End If
        Next
        Return buffer.ToString().Trim()
    End Function
End Class


Public Class ParserFuncDefList
    Inherits SortedDictionary(Of String, ParserFuncDef)

    Public Sub New()

    End Sub

    Public Sub New(ByVal XMLDefFileName As String)
        LoadFromFile(XMLDefFileName)
    End Sub

    Public Sub LoadFromFile(ByVal XMLDefFileName As String)
        If System.IO.File.Exists(XMLDefFileName) Then
            Dim XMLdoc As New System.Xml.XmlDocument()
            XMLdoc.Load(XMLDefFileName)
            If XMLdoc.DocumentElement.Name = "FunctionDefinition" AndAlso _
               (XMLdoc.DocumentElement.ChildNodes(0).Name = "ID") AndAlso _
               (XMLdoc.DocumentElement.ChildNodes(1).Name = "Version") AndAlso _
               (XMLdoc.DocumentElement.ChildNodes(2).Name = "Functions") Then

                For Each node As System.Xml.XmlNode In XMLdoc.DocumentElement.ChildNodes(2).ChildNodes
                    If node.Name = "Function" Then
                        Dim tmpFuncDef As New ParserFuncDef(node)
                        Me.Add(tmpFuncDef.Name.ToUpper(), tmpFuncDef)
                    End If
                Next
            Else

                Throw New Exception(String.Format("'{0}' is an invalid Function Definition!", XMLDefFileName))
            End If
        Else
            Throw New Exception(String.Format("File '{0}' does not exist!", XMLDefFileName))
        End If

    End Sub
End Class




Public Class ParserFuncDef_ItemList
    Inherits System.Collections.ObjectModel.Collection(Of ParserFuncDef_Item)
End Class



Public MustInherit Class ParserFuncDef_Item

    Protected _Parent As ParserFuncDef_Item
    Protected _Children As ParserFuncDef_ItemList

    Public ReadOnly Property Parent() As ParserFuncDef_Item
        Get
            Return _Parent
        End Get
    End Property

    Public ReadOnly Property HasChildren() As Boolean
        Get
            Return (_Children IsNot Nothing) AndAlso _Children.Count > 0
        End Get
    End Property

    Public ReadOnly Property Children() As ParserFuncDef_ItemList
        Get
            Return _Children
        End Get
    End Property

    Public MustOverride ReadOnly Property ItemType() As ParserFuncDef_ItemType
End Class


Public Class ParserFuncDef_Parentesis
    Inherits ParserFuncDef_Item

    Public Sub New(ByVal ItemGroup As ParserFuncDef_ItemList, ByVal Parent As ParserFuncDef_Item)
        _Children = ItemGroup
        _Parent = Parent
    End Sub


    Public Overloads Overrides Function ToString() As String
        Dim buffer As New System.Text.StringBuilder()
        buffer.Append("(")

        For Each item As ParserFuncDef_Item In _Children
            buffer.Append(item.ToString())
            buffer.Append(" ")
        Next

        Return buffer.ToString().Trim() & ")"
    End Function

    Public Overloads Overrides ReadOnly Property ItemType() As ParserFuncDef_ItemType
        Get
            Return ParserFuncDef_ItemType.Parentesis
        End Get
    End Property
End Class

Public Class ParserFuncDef_OptionalGroup
    Inherits ParserFuncDef_Item

    Private _RepeatType As ParserFuncDef_OptionalRepeatType

    Public Sub New(ByVal ItemGroup As ParserFuncDef_ItemList, ByVal Parent As ParserFuncDef_Item)
        Me.New(ItemGroup, ParserFuncDef_OptionalRepeatType.[Optional], Parent)
    End Sub

    Public Sub New(ByVal ItemGroup As ParserFuncDef_ItemList, ByVal RepeatType As ParserFuncDef_OptionalRepeatType, ByVal Parent As ParserFuncDef_Item)
        _Children = ItemGroup
        _RepeatType = RepeatType
        _Parent = Parent
    End Sub

    Public Property RepeatType() As ParserFuncDef_OptionalRepeatType
        Get
            Return _RepeatType
        End Get
        Set(ByVal value As ParserFuncDef_OptionalRepeatType)
            _RepeatType = value
        End Set
    End Property

    Public Overloads Overrides Function ToString() As String
        Dim buffer As New System.Text.StringBuilder()
        If _RepeatType <> ParserFuncDef_OptionalRepeatType.Group Then
            buffer.Append("[")
        Else
            buffer.Append("{")
        End If

        For Each item As ParserFuncDef_Item In _Children
            buffer.Append(item.ToString())
            buffer.Append(" ")
        Next

        If _RepeatType = ParserFuncDef_OptionalRepeatType.Repeat Or _RepeatType = ParserFuncDef_OptionalRepeatType.RepeatOptional Then
            buffer.Append(" ...")
        End If

        If _RepeatType <> ParserFuncDef_OptionalRepeatType.Group Then
            Return buffer.ToString().TrimEnd() & "]"
        Else
            Return buffer.ToString().TrimEnd() & "}"
        End If

    End Function

    Public Overloads Overrides ReadOnly Property ItemType() As ParserFuncDef_ItemType
        Get
            Return ParserFuncDef_ItemType.OptionalGroup
        End Get
    End Property
End Class


Public Class ParserFuncDef_Alternative
    Inherits ParserFuncDef_Item

    Public Sub New(ByVal ItemGroup As ParserFuncDef_ItemList, ByVal Parent As ParserFuncDef_Item)
        _Children = ItemGroup
        _Parent = Parent
    End Sub

    Public Overloads Overrides Function ToString() As String
        Dim buffer As New System.Text.StringBuilder()

        For i As Integer = 0 To _Children.Count - 1
            buffer.Append(_Children(i).ToString())
            If i < _Children.Count - 1 Then
                buffer.Append(" | ")
            End If
        Next

        Return buffer.ToString()
    End Function

    Public Overloads Overrides ReadOnly Property ItemType() As ParserFuncDef_ItemType
        Get
            Return ParserFuncDef_ItemType.Alternative
        End Get
    End Property
End Class


Public Class ParserFuncDef_Designator
    Inherits ParserFuncDef_Item

    Private _Value As String
    Private _Type As ParserFuncDef_DesignatorType

    Public Sub New(ByVal Value As String, ByVal Parent As ParserFuncDef_Item)
        Me.New(Value, ParserFuncDef_DesignatorType.Designator, Parent)
    End Sub

    Public Sub New(ByVal Value As String, ByVal Type As ParserFuncDef_DesignatorType, ByVal Parent As ParserFuncDef_Item)
        _Value = Value
        _Type = Type
        _Parent = Parent
    End Sub

    Public Property Value() As String
        Get
            Return _Value
        End Get
        Set(ByVal value As String)
            _Value = value
        End Set
    End Property

    Public Property Type() As ParserFuncDef_DesignatorType
        Get
            Return _Type
        End Get
        Set(ByVal value As ParserFuncDef_DesignatorType)
            _Type = value
        End Set
    End Property

    Public Overloads Overrides Function ToString() As String
        Return _Value
    End Function

    Public Overloads Overrides ReadOnly Property ItemType() As ParserFuncDef_ItemType
        Get
            If _Type = ParserFuncDef_DesignatorType.Designator Then
                Return ParserFuncDef_ItemType.Designator
            Else
                Return ParserFuncDef_ItemType.Separator
            End If
        End Get
    End Property
End Class


Public Class ParserFuncDef_Expression
    Inherits ParserFuncDef_Item

    Private _Name As String
    Private _Type As ReturnType
    Private _Description As String

    Public Sub New(ByVal Name As String, ByVal Parent As ParserFuncDef_Item)
        Me.New(Name, ReturnType.Any, "", Parent)
    End Sub

    Public Sub New(ByVal Name As String, ByVal Type As ReturnType, ByVal Parent As ParserFuncDef_Item)
        Me.New(Name, Type, "", Parent)
    End Sub

    Public Sub New(ByVal Name As String, ByVal Type As ReturnType, ByVal Description As String, ByVal Parent As ParserFuncDef_Item)
        _Name = Name
        _Type = Type
        _Description = Description
        _Parent = Parent
    End Sub

    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property

    Public Property Type() As ReturnType
        Get
            Return _Type
        End Get
        Set(ByVal value As ReturnType)
            _Type = value
        End Set
    End Property

    Public Property Description() As String
        Get
            Return _Description
        End Get
        Set(ByVal value As String)
            _Description = value
        End Set
    End Property

    Public Overloads Overrides Function ToString() As String
        Return _Name
    End Function

    Public Overloads Overrides ReadOnly Property ItemType() As ParserFuncDef_ItemType
        Get
            Return ParserFuncDef_ItemType.Expression
        End Get
    End Property
End Class

